#include <stdio.h>
#include <stdlib.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>

int main(int argc, char *argv[]) {
    if (argc < 3) {
        fprintf(stderr, "Usage: %s <input_file> <output_url>\n", argv[0]);
        return -1;
    }

    const char *input_file = argv[1];
    const char *output_url = argv[2];

    av_register_all();
    avformat_network_init();

    // 打开输入文件
    AVFormatContext *input_format_context = NULL;
    if (avformat_open_input(&input_format_context, input_file, NULL, NULL) < 0) {
        fprintf(stderr, "Could not open input file: %s\n", input_file);
        return -1;
    }
    printf("Successfully opened input file: %s\n", input_file);

    // 查找流信息
    if (avformat_find_stream_info(input_format_context, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        avformat_close_input(&input_format_context);
        return -1;
    }

    // 创建输出格式上下文
    AVFormatContext *output_format_context = NULL;
    avformat_alloc_output_context2(&output_format_context, NULL, "mpegts", output_url);
    if (!output_format_context) {
        fprintf(stderr, "Could not create output context\n");
        avformat_close_input(&input_format_context);
        return -1;
    }

    // 复制输入流到输出流
    for (int i = 0; i < input_format_context->nb_streams; i++) {
        AVStream *input_stream = input_format_context->streams[i];
        AVStream *output_stream = avformat_new_stream(output_format_context, NULL);
        if (!output_stream) {
            fprintf(stderr, "Failed to allocate output stream\n");
            avformat_close_input(&input_format_context);
            avformat_free_context(output_format_context);
            return -1;
        }

        // 复制流参数
        avcodec_parameters_copy(output_stream->codecpar, input_stream->codecpar);
        output_stream->codecpar->codec_tag = 0; // 清除 codec_tag
    }

    // 打开输出 URL
    if (avio_open(&output_format_context->pb, output_url, AVIO_FLAG_WRITE) < 0) {
        fprintf(stderr, "Could not open output URL: %s\n", output_url);
        avformat_close_input(&input_format_context);
        avformat_free_context(output_format_context);
        return -1;
    }
    printf("Successfully opened output URL: %s\n", output_url);
    // 写文件头
    if (avformat_write_header(output_format_context, NULL) < 0) {
        fprintf(stderr, "Error occurred when writing header\n");
        avio_closep(&output_format_context->pb);
        avformat_close_input(&input_format_context);
        avformat_free_context(output_format_context);
        return -1;
    }

    // 读取输入包并写入输出
    AVPacket packet;
    while (av_read_frame(input_format_context, &packet) >= 0) {
        AVStream *input_stream = input_format_context->streams[packet.stream_index];
        AVStream *output_stream = output_format_context->streams[packet.stream_index];

        // 转换时间戳
        packet.pts = av_rescale_q(packet.pts, input_stream->time_base, output_stream->time_base);
        packet.dts = av_rescale_q(packet.dts, input_stream->time_base, output_stream->time_base);
        packet.duration = av_rescale_q(packet.duration, input_stream->time_base, output_stream->time_base);
        packet.stream_index = output_stream->index;

        // 写入包
        av_interleaved_write_frame(output_format_context, &packet);
        av_packet_unref(&packet);
    }

    // 写文件尾
    av_write_trailer(output_format_context);

    // 清理
    avio_closep(&output_format_context->pb);
    avformat_close_input(&input_format_context);
    avformat_free_context(output_format_context);

    return 0;
}

/*
代码说明
1. 初始化 FFmpeg：
使用 av_register_all() 和 avformat_network_init() 初始化 FFmpeg。
打开输入文件：
使用 avformat_open_input() 打开输入视频文件。
3. 查找流信息：
使用 avformat_find_stream_info() 查找输入文件的流信息。
4. 创建输出格式上下文：
使用 avformat_alloc_output_context2() 创建输出格式上下文。
复制输入流到输出流：
遍历输入流，使用 avformat_new_stream() 创建输出流，并复制流参数。
6. 打开输出 URL：
使用 avio_open() 打开输出 URL。
7. 写文件头：
使用 avformat_write_header() 写入文件头。
读取输入包并写入输出：
使用 av_read_frame() 读取输入包，并使用 av_interleaved_write_frame() 写入输出。
9. 写文件尾：
使用 av_write_trailer() 写入文件尾。
10 清理：
关闭输入和输出上下文，释放资源。
3. 编译和运行
gcc -o ts_push ts_push.c -lavformat -lavcodec -lavutil
./ts_push input.mp4 udp://<destination_ip>:<port>
*/